//
//  FunctionMacros.h
//  SPKit
//
//  Created by LSP on 16/7/26.
//  Copyright © 2016年 SP. All rights reserved.
//

#ifndef FunctionMacros_h
#define FunctionMacros_h

#import "Metamacros.h"

//********* onExit Begin ************/ 
/* onExit */
/* onExit */ #define metamacro_concat(A, B) \
/* onExit */ metamacro_concat_(A, B)
/* onExit */ #define metamacro_concat_(A, B) A ## B
/* onExit */
/* onExit */ #if DEBUG
/* onExit */ #define ext_keywordify autoreleasepool {}
/* onExit */ #else
/* onExit */ #define ext_keywordify try {} @catch (...) {}
/* onExit */ #endif

/* onExit */
/* onExit */ typedef void (^ext_cleanupBlock_t)();
/* onExit */ void ext_executeCleanupBlock (__strong ext_cleanupBlock_t *block) {
/* onExit */    (*block)();
/* onExit */ }
/* onExit */
/* onExit */ #define onExit \
/* onExit */ ext_keywordify \
/* onExit */ __strong ext_cleanupBlock_t metamacro_concat(ext_exitBlock_, __LINE__) __attribute__((cleanup(ext_executeCleanupBlock), unused)) = ^
/* onExit */
//********* onExit End **************/



/**
 * Creates \c __weak shadow variables for each of the variables provided as
 * arguments, which can later be made strong again with #strongify.
 *
 * This is typically used to weakly reference variables in a block, but then
 * ensure that the variables stay alive during the actual execution of the block
 * (if they were live upon entry).
 *
 * See #strongify for an example of usage.
 */
#define weakify(...) \
ext_keywordify \
metamacro_foreach_cxt(ext_weakify_,, __weak, __VA_ARGS__)

/**
 * Like #weakify, but uses \c __unsafe_unretained instead, for targets or
 * classes that do not support weak references.
 */
#define unsafeify(...) \
ext_keywordify \
metamacro_foreach_cxt(ext_weakify_,, __unsafe_unretained, __VA_ARGS__)

/**
 * Strongly references each of the variables provided as arguments, which must
 * have previously been passed to #weakify.
 *
 * The strong references created will shadow the original variable names, such
 * that the original names can be used without issue (and a significantly
 * reduced risk of retain cycles) in the current scope.
 *
 * @code
 id foo = [[NSObject alloc] init];
 id bar = [[NSObject alloc] init];
 @weakify(foo, bar);
 // this block will not keep 'foo' or 'bar' alive
 BOOL (^matchesFooOrBar)(id) = ^ BOOL (id obj){
 // but now, upon entry, 'foo' and 'bar' will stay alive until the block has
 // finished executing
 @strongify(foo, bar);
 return [foo isEqual:obj] || [bar isEqual:obj];
 };
 * @endcode
 */
#define strongify(...) \
ext_keywordify \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
metamacro_foreach(ext_strongify_,, __VA_ARGS__) \
_Pragma("clang diagnostic pop")



#define ext_weakify_(INDEX, CONTEXT, VAR) \
CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR);

#define ext_strongify_(INDEX, VAR) \
__strong __typeof__(VAR) VAR = metamacro_concat(VAR, _weak_);


#endif /* FunctionMacros_h */
